#!/usr/bin/python3
"""
Change DNF configuration.

The stage changes persistent DNF configuration on the filesystem. Currently,
only DNF variables can be defined.
"""

import os
import sys
import iniparse

import osbuild.api


SCHEMA = r"""
"definitions": {
  "variable": {
    "type": "object",
    "additionalProperties": false,
    "required": ["name", "value"],
    "description": "DNF variable to configure persistently.",
    "properties": {
      "name": {
        "type": "string",
        "pattern": "^[a-z0-9_]+$",
        "description": "Name of the variable."
      },
      "value": {
        "type": "string",
        "description": "Value of the variable."
      }
    }
  },
  "config_main": {
    "ip_resolve": {
      "type": "string",
      "enum": ["4", "IPv4", "6", "IPv6"],
      "description": "Determines how DNF resolves host names."
    }
  }
},
"additionalProperties": false,
"description": "DNF configuration.",
"properties": {
  "variables": {
    "type": "array",
    "description": "DNF variables to configure persistently.",
    "items": {
        "$ref": "#/definitions/variable"
    }
  },
  "config": {
    "additionalProperties": false,
    "type": "object",
    "description": "DNF global configuration.",
    "properties": {
      "main": {
        "$ref": "#/definitions/config_main"
      }
    }
  }
}
"""


def configure_variable(tree, name, value):
    """
    Creates a persistent DNF configuration for the given variable name and
    value.

    From DNF.CONF(5):
    Filenames may contain only alphanumeric characters and underscores and be
    in lowercase.
    """
    vars_directory = "/etc/dnf/vars"

    with open(f"{tree}{vars_directory}/{name}", "w") as f:
        f.write(value + "\n")


def make_value(value):
    val = str(value)
    return val


def make_section(cfg, name, settings):
    if not cfg.has_section(name):
        cfg.add_section(name)

    for key, value in settings.items():
        val = make_value(value)
        cfg.set(name, key, val)


def make_dnf_config(tree, config_options):
    """
    Merges the given config object into /etc/dnf/dnf.conf, overwriting existing
    values.
    """
    dnf_config_path = f"{tree}/etc/dnf/dnf.conf"
    dnf_config = iniparse.SafeConfigParser()

    try:
        with open(dnf_config_path, "r") as f:
            dnf_config.readfp(f)
    except FileNotFoundError:
        print(f"Warning: DNF configuration file '{dnf_config_path}' does not exist, will create it.")
        os.makedirs(f"{tree}/etc/dnf", exist_ok=True)

    for section, items  in config_options.items():
        make_section(dnf_config, section, items)

    with open(dnf_config_path, "w") as f:
        os.fchmod(f.fileno(), 0o644)
        dnf_config.write(f)


def main(tree, options):
    variables = options.get("variables", [])

    for variable in variables:
        configure_variable(tree, variable["name"], variable["value"])

    config_options = options.get("config")
    if config_options:
        make_dnf_config(tree, config_options)

    return 0


if __name__ == '__main__':
    args = osbuild.api.arguments()
    r = main(args["tree"], args["options"])
    sys.exit(r)
